package org.multi.core;


import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.multi.core.function.TripleConsumer;
import org.multi.core.state.MutableState;

public interface Gatherer<T, A, R> {

    static <T, A, R> Gatherer<T, A, R> map(Function<T, R> function) {
        return new Gatherers<>(() -> null, (_value, element, consumer) -> consumer.accept(function.apply(element)), (state, consumer) -> {
        });
    }

    static <T, A> Gatherer<T, A, T> filter(Predicate<T> predicate) {
        TripleConsumer<A, T, Consumer<T>> accumulator = (_value, element, consumer) -> {
            if (predicate.test(element)) {
                consumer.accept(element);
            }
        };
        return new Gatherers<>(() -> null, accumulator, (state, consumer) -> {
        });
    }

    static <T, R> Gatherer<T, MutableState<R>, R> scan(Supplier<R> initial, BiFunction<R, T, R> scanner) {
        TripleConsumer<MutableState<R>, T, Consumer<R>> accumulator = (state, element, consumer) -> {
            consumer.accept((state.value = scanner.apply(state.value, element)));
        };
        return new Gatherers<>(() -> new MutableState<>(initial.get()), accumulator, (state, consumer) -> {
        });
    }

    /**
     * 提供初始值
     */
    Supplier<A> supplier();

    /**
     * 让流中元素与初始值进行处理
     */
    TripleConsumer<A, T, Consumer<R>> accumulator();

    /**
     * 最后处理返回值
     */
    BiConsumer<A, Consumer<R>> finisher();

    class Gatherers<T, A, R> implements Gatherer<T, A, R> {
        Supplier<A> supplier;
        TripleConsumer<A, T, Consumer<R>> accumulator;
        BiConsumer<A, Consumer<R>> finisher;

        public Gatherers(Supplier<A> supplier, TripleConsumer<A, T, Consumer<R>> accumulator, BiConsumer<A, Consumer<R>> finisher) {
            this.supplier = supplier;
            this.accumulator = accumulator;
            this.finisher = finisher;
        }

        @Override
        public Supplier<A> supplier() {
            return supplier;
        }

        @Override
        public TripleConsumer<A, T, Consumer<R>> accumulator() {
            return accumulator;
        }

        @Override
        public BiConsumer<A, Consumer<R>> finisher() {
            return finisher;
        }
    }
}
